package com.xhj.ipersistent.executor;

import com.xhj.ipersistent.config.Configuration;
import com.xhj.ipersistent.mapping.BoundSql;
import com.xhj.ipersistent.mapping.MappedStatement;
import com.xhj.ipersistent.mapping.ParameterMapping;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * SimpleExecutor
 *
 * @author XJks
 * @description 简单执行器
 */
public class SimpleExecutor extends BaseExecutor {
    public SimpleExecutor(Configuration configuration) {
        super(configuration);
    }

    @Override
    protected int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        // 获取数据库连接
        Connection connection = getConnection();
        // 获取BoundSql对象
        BoundSql boundSql = ms.getBoundSql();
        // 获取BoundSql中的sql语句和参数名称列表
        String sql = boundSql.getSql();
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        // 预编译SQL语句，得到PreparedStatement对象
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        // 处理参数不为null的情况，如果参数为null，则不设置参数
        if (parameter != null) {
            // 获取参数类型
            Class<?> parameterTypeClass = parameter.getClass();
            // 遍历参数名称列表，设置参数值
            if (parameterMappings != null && parameterMappings.size() > 0) {
                for (int i = 0; i < parameterMappings.size(); i++) {
                    ParameterMapping parameterMapping = parameterMappings.get(i);
                    // 获取参数名称
                    String parameterName = parameterMapping.getParameterName();
                    // 通过反射获取参数值
                    Object parameterValue = null;
                    try {
                        Field declaredField = parameterTypeClass.getDeclaredField(parameterName);
                        declaredField.setAccessible(true);
                        parameterValue = declaredField.get(parameter);
                    } catch (Exception e) {
                        throw new SQLException(e);
                    }
                    // 设置参数
                    preparedStatement.setObject(i + 1, parameterValue);
                }
            }
        }
        // 执行SQL语句，获取结果
        return preparedStatement.executeUpdate();
    }

    @Override
    protected <E> List<E> doQuery(MappedStatement ms, Object parameter, BoundSql boundSql) throws SQLException {
        // 获取数据库连接
        Connection connection = getConnection();
        // 获取BoundSql中的sql语句和参数名称列表
        String sql = boundSql.getSql();
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        // 预编译SQL语句，得到PreparedStatement对象
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        // 处理参数不为null的情况，如果参数为null，则不设置参数
        if (parameter != null) {
            // 获取参数类型
            Class<?> parameterTypeClass = parameter.getClass();
            // 遍历参数名称列表，设置参数值
            if (parameterMappings != null && parameterMappings.size() > 0) {
                for (int i = 0; i < parameterMappings.size(); i++) {
                    ParameterMapping parameterMapping = parameterMappings.get(i);
                    // 获取参数名称
                    String parameterName = parameterMapping.getParameterName();
                    // 通过反射获取参数值
                    Object parameterValue = null;
                    try {
                        Field declaredField = parameterTypeClass.getDeclaredField(parameterName);
                        declaredField.setAccessible(true);
                        parameterValue = declaredField.get(parameter);
                    } catch (Exception e) {
                        throw new SQLException(e);
                    }
                    // 设置参数
                    preparedStatement.setObject(i + 1, parameterValue);
                }
            }
        }
        // 执行SQL语句，获取结果集
        resultSet = preparedStatement.executeQuery();
        // 处理结果集
        List<E> resultList = new ArrayList<E>();
        while (resultSet.next()) {
            // 获取结果集元数据，其中包含字段名，字段值等信息
            ResultSetMetaData metaData = resultSet.getMetaData();
            // 获取返回值类型
            String resultType = ms.getResultType();
            // 通过反射创建返回值类型的实例对象
            Class<?> resultTypeClass = null;
            Object object = null;
            try {
                resultTypeClass = Class.forName(resultType);
                object = resultTypeClass.newInstance();
            } catch (Exception e) {
                throw new SQLException(e);
            }
            // 填充对象属性
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                try {
                    // 获取结果集元数据的第i列的列名
                    String columnName = metaData.getColumnName(i);
                    // 根据列名获取当前行的列值
                    Object value = resultSet.getObject(columnName);
                    // 通过属性描述器获取对象某些属性的读写方法，然后调用读写方法设置属性值
                    PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                    // 获取写方法
                    Method writeMethod = propertyDescriptor.getWriteMethod();
                    // 使用反射调用写方法，设置属性值
                    writeMethod.invoke(object, value);
                } catch (Exception e) {
                    throw new SQLException(e);
                }
            }
            resultList.add((E) object);
        }
        return resultList;
    }
}
